module expd.semantic;
import expd.tree;
import expd.itree;
import expd.node;
import expd.ibase;
import expd.itoken;
import expd.istack;
import expd.stack;
import _ver = expd._version;

version ( dbg ) {
  import expd.meta;
  mixin ( DebugTrick() );
}

class Walker : Streamable! ( ITree!Token ), _ver.Versionable {
    alias node!Token Node;
    ITree!Token tree;
    IStack! ( Node * ) stack;
    public this() {};
    //iterated version
    ///Push to do semantic analysis on a tree.
    void push ( ITree!Token x ) {
      size_t LINE;
      version ( dbg ) synchronized _objout ( "WALKER: pushed" );
      tree = x;
      auto ptr = &tree.getNode();//not recommended
      stack.push ( null );
      while ( true ) {
          version ( dbg3 ) synchronized _objout ( "WALKER: working with ", *ptr, " @ ", ptr );
          if ( ptr.sym.type != TOKEN.NL ) {
              if ( stack.peek() != ptr ) {

                  doNode ( *ptr );
                  if ( ptr.down !is null ) {

                      stack.push ( ptr );
                      ptr = ptr.down;
                      continue;
                    }
                }
              else stack.pop();
            }
          else LINE++;

          if ( ptr.next !is null ) {
              ptr = ptr.next;
              continue;
            }
          if ( ptr.up !is null ) ptr = ptr.up;
          else return;
        }
    }
    void flush() {}
    abstract void doNode ( ref Node toProc );
    mixin ( _ver.genVersion! ( 1, 0, 0 ) );
}

class DelegateWalker : Walker {
    this() {
      stack = new Stack! ( Node * ) ();
    }
    private void delegate ( ref Node, Walker ) _xptr;

    void setFun ( void delegate ( ref Node, Walker ) ptr ) {
      _xptr = ptr;
    }
    override void doNode ( ref Node toProc ) {
      assert ( _xptr !is null );
      _xptr ( toProc, this );
    }
    mixin ( _ver.genVersion! ( 1, 0, 0 ) );
}
